/*
	Copyright (c) 2012 by karmaleaving@qq.com. All rights RESERVED.
*/

#ifndef __SHARED_PTR_H_VERSION_SSTD__
#define __SHARED_PTR_H_VERSION_SSTD__
#include "throw.hpp"
#include "./memory.hpp" // for class <auto_ptr>
SSTL_BEGIN
template<class Type>
class shared_ptr
{
protected:
	struct inner_data;
	inner_data* _data;
public:
	typedef Type Type;
	shared_ptr(Type* val = 0)
		: _data(new inner_data<Type>(val))
	{}
	~shared_ptr()
	{
		_data->release();
	}
	shared_ptr(shared_ptr<Type> const& other)
		: _data(other._data->reference())
	{
	}
	void operator = (shared_ptr<Type> const& other)
	{
		_data->release();
		_data = other._data->reference();
	}
	void operator = (Type* val)
	{
		_data->release();
		_data = new inner_data<Type>(val);
	}
	bool operator == (shared_ptr<Type> const& other) const
	{
		return _data == other._data;
	}
	bool operator == (const Type* const other) const
	{
		return _data->visit() == other;
	}
	bool valid() const
	{
		return (_data->visit() != 0);
	}
	Type& operator * ()
	{
		ASSERT(valid());
		return *(_data->visit());
	}
	const Type& operator * () const
	{
		ASSERT(valid());
		return *(_data->visit());
	}
	Type& operator -> ()
	{
		ASSERT(valid());
		return *(_data->visit());
	}
	const Type& operator -> () const
	{
		ASSERT(valid());
		return *(_data->visit());
	}
protected:
	struct inner_data
	{
	protected:
		Type* _value;
		int _ref;
		inner_data(inner_data const&);
		~inner_data()
		{
			DELETEIT(_value);
		}
	public:
		inner_data(Type* val) : _value(val), _ref(1)
		{
		}
		Type* visit() const
		{
			return _value;
		}
		inner_data<Type>* reference()
		{
			++_ref; return this;
		}
		void release()
		{
			if (!--_ref) delete this;
		}
	};
};
SSTL_BEGIN
#endif // __SHARED_PTR_H_VERSION_SSTD__
